# include "VideoCapture.h"
# include "d3d11.h"

VideoCapture::VideoCapture(IDXGIAdapter1* _adapter, IDXGIOutput1* _output): m_adapter(_adapter)
{
	DXGI_OUTPUT_DESC desc;
	_output->GetDesc(&desc);
	this->m_width = desc.DesktopCoordinates.right - desc.DesktopCoordinates.left;
	this->m_height = desc.DesktopCoordinates.bottom - desc.DesktopCoordinates.top;
	if (this->m_device == nullptr) {
		HRESULT hr = D3D11CreateDevice(this->m_adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, nullptr, 0, D3D11_SDK_VERSION, this->m_device.GetAddressOf(), nullptr, this->m_context.GetAddressOf());
		if (this->m_device != nullptr) {
			_output->DuplicateOutput(this->m_device.Get(), this->m_duplication.GetAddressOf());
		}
	}
}

bool VideoCapture::capture()
{
	DXGI_OUTDUPL_FRAME_INFO info;
	Microsoft::WRL::ComPtr<IDXGIResource> desktop = nullptr;
	this->m_duplication->ReleaseFrame();
	HRESULT hr = this->m_duplication->AcquireNextFrame(0, &info, desktop.GetAddressOf());
	if (hr == DXGI_ERROR_WAIT_TIMEOUT) {
		return false;
	}
	if (desktop == nullptr) {
		return false;
	}
	hr = desktop->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(this->m_image.ReleaseAndGetAddressOf()));
	if (FAILED(hr)) {
		this->m_duplication->ReleaseFrame();
		return false;
	}
	return true;
}

int VideoCapture::width() const
{
	return this->m_width;
}

int VideoCapture::height() const
{
	return this->m_height;
}

ID3D11Texture2D* VideoCapture::getImageTexture() const
{
	return this->m_image.Get();
}

ID3D11Device* VideoCapture::getDevice() const
{
	return this->m_device.Get();
}

ID3D11DeviceContext* VideoCapture::getContext() const
{
	return this->m_context.Get();
}

VideoCapture::~VideoCapture()
{
}

int VideoCapture::enumCaptureToVector(std::vector<VideoCapture*>*& _videoCaptureVector)
{
	_videoCaptureVector = new std::vector<VideoCapture*>();
	Microsoft::WRL::ComPtr<IDXGIFactory2> factory = nullptr;
	HRESULT hr;
	hr = CreateDXGIFactory1(__uuidof(IDXGIFactory2), (void**)(factory.GetAddressOf()));
	if (FAILED(hr)) {
		return CREAT_DXGIFACTORY_ERROR;
	}
	for (UINT i = 0;; ++i) {
		IDXGIAdapter2* adapter = nullptr;
		hr = factory->EnumAdapters1(i, reinterpret_cast<IDXGIAdapter1**>(&adapter));
		if (hr == DXGI_ERROR_NOT_FOUND) {
			return DXGI_FACTORY_NOT_FOUND;
		}
		if (FAILED(hr)) {
			return FACTORY_FAILD;
		}
		DXGI_ADAPTER_DESC1 desc;

		hr = adapter->GetDesc1(&desc);

		if (FAILED(hr)) {
			return ADAPTER_FAILD;
		}
		for (UINT j = 0;; ++j) {
			Microsoft::WRL::ComPtr<IDXGIOutput> output = nullptr;
			hr = adapter->EnumOutputs(j, &output);
			if (hr == DXGI_ERROR_NOT_FOUND) {
				return OUTPUT_NOT_FOUND;
			}
			if (FAILED(hr)) {
				return OUTPUT_FAILD;
			}
			Microsoft::WRL::ComPtr<IDXGIOutput1> output1 = nullptr;
			output->QueryInterface(__uuidof(IDXGIOutput1), reinterpret_cast<void**>(output1.GetAddressOf()));
			_videoCaptureVector->push_back(new VideoCapture(adapter, output1.Get()));
		}
	}
	return S_OK;
}

void VideoCapture::releaseCaputreFromVector(std::vector<VideoCapture*>* _videoCaptureVector)
{
	if (_videoCaptureVector == nullptr) {
		return;
	}
	for (auto item : *_videoCaptureVector) {
		delete item;
	}
	delete _videoCaptureVector;
}
